/*
 * Copyright 2013 Glassy Cinema.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package hu.glassy.core.config;

import java.sql.Connection;
import java.util.Properties;
import javax.sql.DataSource;
import liquibase.integration.spring.SpringLiquibase;
import org.hibernate.ejb.HibernatePersistence;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

/**
 * Configuration of the data access layer
 *
 * @author molnar.alexander@sonrisa.hu
 */
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "hu.glassy.core.repositories")
@PropertySource("classpath:/conf/app-config.properties")
public class DatabaseConfig implements TransactionManagementConfigurer
{

  // --------------------------------------------------
  // ~ Parameters
  // --------------------------------------------------
  // Entity manager packages to scan
  @Value("${entity.manager.packages.to.scan}")
  private String packagesToScan;
  // Hibernate parameters
  @Value("${hibernate.config.dialect}")
  private String hibernateDialect;
  @Value("${hibernate.config.format.sql}")
  private String hibernateFormatSql;
  @Value("${hibernate.config.ejb.naming.strategy}")
  private String hibernateEjbNamingStrategy;
  @Value("${hibernate.config.hbm2ddl.mode}")
  private String hibernateHbm2ddlMode;
  @Value("${hibernate.config.showsql}")
  private boolean hibernateShowSql;
  @Value("${hibernate.config.generate.ddl}")
  private boolean generateDdl;

  @Bean
  public DataSource dataSource()
  {
    return new JndiDataSourceLookup().getDataSource("jdbc/glassyDB");
  }

  @Bean(name = "transactionManager")
  public JpaTransactionManager transactionManager()
  {
    return new JpaTransactionManager(entityManagerFactory().getObject());
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory()
  {
    final LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();

    entityManagerFactoryBean.setDataSource(dataSource());
    entityManagerFactoryBean.setPackagesToScan(packagesToScan);
    entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);

    final Properties jpaProterties = new Properties();
    jpaProterties.put("hibernate.dialect", hibernateDialect);
    jpaProterties.put("hibernate.format_sql", hibernateFormatSql);
    jpaProterties.put("hibernate.ejb.naming_strategy", hibernateEjbNamingStrategy);
    //jpaProterties.put("hibernate.hbm2ddl.auto", hibernateHbm2ddlMode);
    entityManagerFactoryBean.setJpaProperties(jpaProterties);

    // JPA vendoradapter
    final HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
    jpaVendorAdapter.setShowSql(hibernateShowSql);
    jpaVendorAdapter.setGenerateDdl(generateDdl);
    jpaVendorAdapter.setDatabasePlatform(hibernateDialect);
    entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);

    return entityManagerFactoryBean;
  }

  public PlatformTransactionManager annotationDrivenTransactionManager()
  {
    return transactionManager();
  }

  @Bean
  public SpringLiquibase springLiquibase() throws Exception
  {
    final SpringLiquibase sl = new SpringLiquibase();
    sl.setDataSource(dataSource());
    sl.setChangeLog("classpath:liquibase/changelog.xml");

    Connection connection = null;

    try
    {
      connection = dataSource().getConnection();
      sl.setDefaultSchema(connection.getCatalog());
    }
    finally
    {
      if (connection != null)
      {
        connection.close();
      }
    }
    return sl;
  }
}
